<template>
  <div>
    <div id="mask"></div>
    <div id="panel">
      <div id="title">
        <div>上传音乐</div>
        <div
          @click="close()"
          id="close"
        >
          X
        </div>
      </div>
      <div id="content">
        <div id="upload-btn">
          <el-upload
            ref="uploadSong"
            :auto-upload="false"
            :on-change="handleChangeSong"
            :limit="1"
            :on-exceed="handleExceedSong"
          >
            <template #trigger>
              <el-button
                type="primary"
                class="btn"
                >选择音乐文件
              </el-button>
            </template>
          </el-upload>
          <el-upload
            ref="uploadLyric"
            :auto-upload="false"
            :on-change="handleChangeLyric"
            :limit="1"
            :on-exceed="handleExceedLyric"
          >
            <template #trigger>
              <el-button
                type="primary"
                class="btn"
                >选择歌词文件
              </el-button>
            </template>
          </el-upload>
          <el-upload
            ref="uploadTinyImg"
            :auto-upload="false"
            :on-change="handleChangeTinyImg"
            :limit="1"
            :on-exceed="handleExceedTinyImg"
          >
            <template #trigger>
              <el-button
                type="primary"
                class="btn"
                >选择缩略图
              </el-button>
            </template>
          </el-upload>
          <el-upload
            ref="uploadLargeImg"
            :auto-upload="false"
            :on-change="handleChangeLargeImg"
            :limit="1"
            :on-exceed="handleExceedLargeImg"
          >
            <template #trigger>
              <el-button
                type="primary"
                class="btn"
                >选择轮播图
              </el-button>
            </template>
          </el-upload>
        </div>
        <div class="input-info">
          <span class="tip">请输入歌曲名称</span>
          <div>
            <el-input
              v-model="song"
              class="inline-input w-50"
              placeholder="..."
            />
          </div>
        </div>
        <div class="input-info">
          <span class="tip">请选择歌曲分类</span>
          <div>
            <el-select
              v-model="genre"
              placeholder="无分类"
            >
              <el-option
                v-for="item in options"
                :key="item.id"
                :value="item.name"
                @click="
                  () => {
                    songInfo.genre = item.id
                  }
                "
              />
            </el-select>
          </div>
        </div>
        <div class="input-info">
          <span class="tip">请输入作者姓名</span>
          <div>
            <el-autocomplete
              v-model="artist"
              :fetch-suggestions="querySearch"
              :trigger-on-focus="false"
              clearable
              class="inline-input w-50"
              placeholder="..."
              value-key="name"
            />
          </div>
          <el-checkbox
            v-model="checked"
            label="新作者"
            size="large"
          />
        </div>
        <div
          class="input-info"
          v-if="checked"
        >
          <span class="tip">请输入作者简介</span>
          <el-input
            v-model="textarea"
            style="width: 240px"
            :autosize="{ minRows: 2, maxRows: 4 }"
            type="textarea"
            placeholder="..."
          />
        </div>
        <div class="center">
          <el-button
            type="success"
            class="btn"
            @click="submit"
            >点击上传
          </el-button>
          <p
            id="wan"
            v-if="song === null || song.trim() === ''"
          >
            {{ errorMessage }}
          </p>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { ElMessage, genFileId, type UploadInstance, type UploadProps, type UploadRawFile } from 'element-plus'
import type { ArtistVO, FileDTO, GenreDTO } from '@/types/song'
import { getArtistListAPI, getGeneAPI, postSongAPI } from '@/services/songService.ts'
import type { NewSongInfo } from '@/types/song'
import { ApiException } from '@/utils/exception/api-exception.ts'
import type { UnifyResponse } from '@/types/result'

const emit = defineEmits(['close'])
const uploadSong = ref<UploadInstance>()
const songInfo = ref<NewSongInfo>({
  name: null,
  artist: null,
  bio: null,
  genre: null,
  tinyImg: null,
  largeImg: null,
  lyric: null,
})
const uploadTinyImg = ref<UploadInstance>()
const uploadLargeImg = ref<UploadInstance>()
const uploadLyric = ref<UploadInstance>()
const artist = ref<string>()
const artistList = ref<ArtistVO[]>([])
const song = ref<string | null>(null)
const genre = ref<String>()
const options = ref<GenreDTO[]>([])
const checked = ref(false)
const textarea = ref('')
const uploaded = ref<FileDTO>({
  uploadedSongFile: null,
  uploadLyric: null,
  uploadedTinyImg: null,
  uploadedLargerImg: null,
})
const errorMessage = ref<string | null>(null)

const handleChangeSong: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
  if (uploadFile.raw) {
    const isMusic = ['audio/flac', 'audio/mpeg'].includes(uploadFile.raw.type)
    if (!isMusic) {
      ElMessage.error('文件只能是 flac或mp3 格式!')
      uploadFiles.pop()
      return
    }
    const isLt100M = uploadFile.raw.size / 1024 / 1024 < 100
    if (!isLt100M) {
      ElMessage.error('文件大小不能超过 100MB!')
      uploadFiles.pop()
      return
    }
  } else {
    ElMessage.error('未知原因上传失败')
    return
  }
  uploaded.value.uploadedSongFile = uploadFile.raw
}

const handleChangeLyric: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
  if (uploadFile.raw) {
    const fileExtension = uploadFile.name.split('.').pop()?.toLowerCase()

    const isLrcFile = fileExtension === 'lrc'

    const isAllowedMimeType = ['text/plain', 'application/octet-stream'].includes(uploadFile.raw.type)

    if (!isLrcFile && !isAllowedMimeType) {
      ElMessage.error('文件只能是 文本或lrc 格式!')
      uploadFiles.pop()
      return
    }
    const isLt100M = uploadFile.raw.size / 1024 / 1024 < 100
    if (!isLt100M) {
      ElMessage.error('文件大小不能超过 100MB!')
      uploadFiles.pop()
      return
    }
  } else {
    ElMessage.error('未知原因上传失败')
    return
  }
  uploaded.value.uploadLyric = uploadFile.raw
  songInfo.value.lyric = uploadFile.name
}

const handleChangeTinyImg: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
  if (uploadFile.raw) {
    const isMp3 = ['image/jpeg', 'image/png'].includes(uploadFile.raw.type)
    if (!isMp3) {
      ElMessage.error('文件只能是 JPG/PNG 格式!')
      uploadFiles.pop()
      return
    }
    const isLt100M = uploadFile.raw.size / 1024 / 1024 < 100
    if (!isLt100M) {
      ElMessage.error('文件大小不能超过 100MB!')
      uploadFiles.pop()
      return
    }
  } else {
    ElMessage.error('未知原因上传失败')
    return
  }
  uploaded.value.uploadedTinyImg = uploadFile.raw
  songInfo.value.tinyImg = uploadFile.name
}

const handleChangeLargeImg: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
  if (uploadFile.raw) {
    const isMp3 = ['image/jpeg', 'image/png'].includes(uploadFile.raw.type)
    if (!isMp3) {
      ElMessage.error('文件只能是 JPG/PNG 格式!')
      uploadFiles.pop()
      return
    }
    const isLt100M = uploadFile.raw.size / 1024 / 1024 < 100
    if (!isLt100M) {
      ElMessage.error('文件大小不能超过 100MB!')
      uploadFiles.pop()
      return
    }
  } else {
    ElMessage.error('未知原因上传失败')
    return
  }
  uploaded.value.uploadedLargerImg = uploadFile.raw
  songInfo.value.largeImg = uploadFile.name
}

const handleExceedSong: UploadProps['onExceed'] = files => {
  uploadSong.value!.clearFiles()
  const file = files[0] as UploadRawFile
  file.uid = genFileId()
  uploadSong.value!.handleStart(file)
}

const handleExceedLyric: UploadProps['onExceed'] = files => {
  uploadLyric.value!.clearFiles()
  const file = files[0] as UploadRawFile
  file.uid = genFileId()
  uploadLyric.value!.handleStart(file)
}

const handleExceedTinyImg: UploadProps['onExceed'] = files => {
  uploadTinyImg.value!.clearFiles()
  const file = files[0] as UploadRawFile
  file.uid = genFileId()
  uploadTinyImg.value!.handleStart(file)
}

const handleExceedLargeImg: UploadProps['onExceed'] = files => {
  uploadLargeImg.value!.clearFiles()
  const file = files[0] as UploadRawFile
  file.uid = genFileId()
  uploadLargeImg.value!.handleStart(file)
}

const createFilter = (queryString: string) => {
  return (artistDTO: ArtistVO) => {
    return artistDTO.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0
  }
}

const querySearch = (queryString: string, cb: any) => {
  const results = queryString ? artistList.value.filter(createFilter(queryString)) : artistList.value
  cb(results)
}

function close() {
  emit('close', 1, false)
}

const submit = async () => {
  if (song.value === null || song.value.trim() === '') {
    errorMessage.value = '歌曲名称不能为空'
    return
  }
  songInfo.value.name = song.value
  songInfo.value.artist = artist.value || null
  songInfo.value.bio = textarea.value || null
  if (!uploaded.value.uploadedSongFile) {
    errorMessage.value = '请选择歌曲文件'
    return
  }

  const formData = new FormData()
  if (uploaded.value.uploadLyric !== null) formData.append('lyric', uploaded.value.uploadLyric)
  if (uploaded.value.uploadedTinyImg !== null) formData.append('tinyImg', uploaded.value.uploadedTinyImg)
  if (uploaded.value.uploadedLargerImg !== null) formData.append('largeImg', uploaded.value.uploadedLargerImg)
  formData.append('song', uploaded.value.uploadedSongFile)

  formData.append('songInfo', JSON.stringify(songInfo.value))

  try {
    const res: UnifyResponse<String> = await postSongAPI(formData)
    if (res.code === 200) {
      ElMessage.success('歌曲上传成功！')
    } else {
      ElMessage.error(res.msg)
    }
    resetForm()
  } catch (error) {
    if (error instanceof ApiException) {
      errorMessage.value = error.message
    } else {
      errorMessage.value = '上传失败，请稍后重试'
      console.error(error)
    }
  }
}

const resetForm = () => {
  songInfo.value = {
    name: null,
    artist: null,
    bio: null,
    genre: null,
    tinyImg: null,
    largeImg: null,
    lyric: null,
  }
  uploaded.value = {
    uploadedSongFile: null,
    uploadLyric: null,
    uploadedTinyImg: null,
    uploadedLargerImg: null,
  }
}

onMounted(async () => {
  try {
    const res: UnifyResponse<GenreDTO[]> = await getGeneAPI()
    options.value = res.data || []
  } catch (error) {
    if (error instanceof ApiException) {
      errorMessage.value = error.message
    } else {
      console.error(error)
    }
  }

  try {
    const res: UnifyResponse<ArtistVO[]> = await getArtistListAPI()
    artistList.value = res.data || []
  } catch (error) {
    if (error instanceof ApiException) {
      errorMessage.value = error.message
    } else {
      console.error(error)
    }
  }
})
</script>

<style scoped>
#mask {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
}

#panel {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 60rem;
  background-color: #c1bbbb;
  border-radius: 2rem;
}

#title {
  background-color: #535353;
  height: 3rem;
  border-radius: 2rem 2rem 0 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 2rem 0 2rem;
  font-weight: bold;
  color: #74ba1d;
}

#close {
  cursor: pointer;
}

#content {
  margin-top: 2rem;
  margin-bottom: 2rem;
  width: 100%;
}

.btn {
  width: 10rem;
  height: 3rem;
}

.input-info {
  width: 30em;
  margin: 0 auto;
  display: flex;
  align-items: center;
}

.input-info :deep(.el-input__wrapper),
.input-info :deep(.el-textarea) {
  margin: 1em;
}

.input-info :deep(.el-select__wrapper) {
  margin: 1em;
  width: 10em;
}

.tip {
  width: 7em;
  color: #0072b5;
  font-weight: bold;
}

#artist div {
  width: 15em;
}

#describe div {
  margin-top: 2em;
}

#upload-btn {
  width: 100%;
  margin: auto;
  display: flex;
  align-items: center;
  justify-content: space-around;
}

#upload-btn :deep(.el-upload-list__item) {
  max-width: 11em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.center {
  margin-top: 1em;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

#wan {
  color: #ff0000;
  margin-top: 0.5em;
}
</style>
